use std::fs::File;
use std::io::BufRead;
use std::io::{self, Read, Seek, SeekFrom};
use std::str;

const MAX_WORD_LEN: usize = 32;

pub fn converter(input: &str, tp: &str) -> String {
    let (index_file_path, data_file_path) = match tp {
        "t2s" => (
            "generator/output/t2s.idx",
            "generator/output/t2s.dat",
        ),
        "s2t" => (
            "generator/output/s2t.idx",
            "generator/output/s2t.dat",
        ),
        _ => return input.to_string(),
    };

    let mut index_file = match File::open(index_file_path) {
        Ok(file) => file,
        Err(e) => {
            println!("无法打开索引文件：{},{:?}", index_file_path,e);
            return input.to_string();
        }
    };

    if let Ok(offset) = binary_search_in_index(&mut index_file, input) {
        if let Ok(result) = read_data_from_offset(data_file_path, offset) {
            return result;
        }
    }

    input.to_string()
}

fn binary_search_in_index(index_file: &mut File, target: &str) -> io::Result<u64> {
    let mut left = 0;
    let file_size = index_file.metadata()?.len();
    let record_size = (MAX_WORD_LEN + 8) as u64;
    let mut right = (file_size / record_size) - 1;

    while left <= right {
        let mid = (left + right) / 2;
        index_file.seek(SeekFrom::Start(mid * record_size))?;

        let mut word_bytes = vec![0u8; MAX_WORD_LEN];
        index_file.read_exact(&mut word_bytes)?;
        let mut offset_bytes = [0u8; 8];
        index_file.read_exact(&mut offset_bytes)?;

        let word = String::from_utf8_lossy(&word_bytes)
            .trim_end_matches(char::from(0))
            .to_string();
        let offset = u64::from_le_bytes(offset_bytes);

        match word.cmp(&target.to_string()) {
            std::cmp::Ordering::Less => {
                left = mid + 1;
            }
            std::cmp::Ordering::Greater => {
                if mid == 0 {
                    break;
                }
                right = mid - 1;
            }
            std::cmp::Ordering::Equal => {
                return Ok(offset);
            }
        }
    }

    Err(io::Error::new(io::ErrorKind::NotFound, "未找到对应的词语"))
}

fn read_data_from_offset(data_file_path: &str, offset: u64) -> io::Result<String> {
    let mut data_file = File::open(data_file_path)?;
    data_file.seek(SeekFrom::Start(offset))?;
    let mut buffer = Vec::new();
    let mut reader = io::BufReader::new(data_file);
    reader.read_until(b'\n', &mut buffer)?;

    if buffer.ends_with(&[b'\n']) {
        buffer.pop();
    }

    let result = String::from_utf8_lossy(&buffer).to_string();

    Ok(result)
}
